package com.cwx.mychat.websocket.context;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.cwx.mychat.entity.constant.CodeConstant;
import com.cwx.mychat.entity.enums.UserContactApplyStatusEnum;
import com.cwx.mychat.entity.po.*;
import com.cwx.mychat.entity.vo.MessageSendVo;
import com.cwx.mychat.entity.enums.MessageTypeEnum;
import com.cwx.mychat.entity.enums.UserContactTypeEnum;
import com.cwx.mychat.entity.vo.ChatInitMessageVo;
import com.cwx.mychat.mappers.*;
import com.cwx.mychat.service.UserContactService;
import com.cwx.mychat.utils.cipher.AESUtils;
import com.cwx.mychat.utils.json.JsonUtil;
import com.cwx.mychat.utils.redis.RedisComponent;
import com.cwx.mychat.utils.stringUtils.StringUtil;
import io.netty.channel.Channel;
import io.netty.channel.group.ChannelGroup;
import io.netty.channel.group.DefaultChannelGroup;
import io.netty.handler.codec.http.websocketx.TextWebSocketFrame;
import io.netty.util.AttributeKey;
import io.netty.util.concurrent.GlobalEventExecutor;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;

import java.util.ArrayList;

import java.util.List;
import java.util.Objects;
import java.util.concurrent.ConcurrentHashMap;
import java.util.stream.Collectors;

/**
 * 作者： cwx
 * 时间： 2024/9/21 8:28
 * 版本： 1.0
 * 注释：
 */
@Slf4j
@Component
public class ChannelContextUtil {

    private static final ConcurrentHashMap<String, Channel> CHANNEL_CONCURRENT_HASH_MAP = new ConcurrentHashMap<>();
    private static final ConcurrentHashMap<String, ChannelGroup> CHANNEL_GROUP_CONCURRENT_HASH_MAP = new ConcurrentHashMap<>();

    @Resource
    private RedisComponent redisComponent;

    @Resource
    private UserInfoMapper userInfoMapper;
    @Resource
    private ChatSessionUserMapper chatSessionUserMapper;

    @Resource
    private ChatMessageMapper chatMessageMapper;

    @Resource
    private UserContactApplyMapper userContactApplyMapper;

    @Resource
    private UserContactService userContactService;

    @Resource
    private GroupInfoMapper groupInfoMapper;

    /**
     * 获取群组通道在线人数
     * @param groupId
     * @return
     */
    public Integer getGroupMemberById(String groupId){
        ChannelGroup channelGroup = CHANNEL_GROUP_CONCURRENT_HASH_MAP.get(groupId);
        if(channelGroup != null){
            return channelGroup.size();
        }
        return 0;
    }


    public void addContext(String userId, Channel channel){
        if(StringUtil.isEmpty(userId)){
            return;
        }
        String channelId = channel.id().toString();
        AttributeKey attributeKey = null;
        if(!AttributeKey.exists(channelId)){
            attributeKey = AttributeKey.newInstance(channelId);
        }else {
            attributeKey = AttributeKey.valueOf(channelId);
        }
        channel.attr(attributeKey).set(userId);
        UserInfo userInfo = userInfoMapper.selectById(userId);
        //获取联系人加入到群通道
        List<String> userContactList = redisComponent.getUserContactBatch(userId);
        log.info("从redis中获取联系人id{}", userContactList);
        if(userContactList != null && userContactList.size() > 0){
            for(String groupId: userContactList){
                if(groupId.startsWith(UserContactTypeEnum.GROUP.getPrefix())){
                    addToGroup(groupId, channel);
                }
            }
        }else{
            //查询数据库
            List<UserContact> userContactList1 = userContactService.selectContact(userInfo);
            List<String> collect = userContactList1.stream().map(UserContact::getContactId).toList();
            log.info("将联系人id{}重新存入redis中", collect);
            redisComponent.saveUserContactBatch(userId, collect);
            for(String groupId: collect){
                if(groupId.startsWith(UserContactTypeEnum.GROUP.getPrefix())){
                    addToGroup(groupId, channel);
                }
            }
        }
        //将通道和心跳进行缓存
        CHANNEL_CONCURRENT_HASH_MAP.put(userId, channel);
        redisComponent.saveUserHeartbeat(userId);
        //给用户发送消息
        Long lastOffTime = userInfo.getLastOffTime();
        if(lastOffTime != null && System.currentTimeMillis() - CodeConstant.MILLIS_SECOND_DAYS_MSG > lastOffTime){
            lastOffTime = System.currentTimeMillis() - CodeConstant.MILLIS_SECOND_DAYS_MSG;
        }
        //查询会话信息，查询用户所有的会话信息
        List<ChatSessionUser> chatSessionUserList = chatSessionUserMapper.selectSessionUserList(userId);
        //对session进行过滤处理
        List<String> contactUserIds = new ArrayList<>();
        List<String> contactGroupIds = new ArrayList<>();
        chatSessionUserList.forEach(chatSessionUser -> {
            //如果当前的userId在contactId中则交换两个值
            if(chatSessionUser.getContactId().equals(userId)){
                System.out.println("获取到" + chatSessionUser);
                String contactId = chatSessionUser.getContactId();
                //这个userId是数据库存的userId，userId只表示是谁加的谁而已
                String chatSessionUserId = chatSessionUser.getUserId();
                chatSessionUser.setUserId(contactId);
                chatSessionUser.setContactId(chatSessionUserId);
            }
            if(chatSessionUser.getContactId().startsWith(UserContactTypeEnum.USER.getPrefix())){
                contactUserIds.add(chatSessionUser.getContactId());
            }
            if(chatSessionUser.getContactId().startsWith(UserContactTypeEnum.GROUP.getPrefix())){
                contactGroupIds.add(chatSessionUser.getContactId());
            }
        });
        //查询联系人头像和昵称,分为群组和联系人
        if(contactUserIds.size() > 0){
            List<UserInfo> userInfos = this.userInfoMapper.selectList(new LambdaQueryWrapper<UserInfo>().select(UserInfo::getUserId, UserInfo::getNickName, UserInfo::getUserAvatar)
                    .in(UserInfo::getUserId, contactUserIds));
            userInfos.forEach(item -> {
                chatSessionUserList.forEach(it -> {
                    if(Objects.equals(it.getContactId(), item.getUserId())){
                        it.setAvatar(item.getUserAvatar());
                        it.setNickName(item.getNickName());
                    }
                });
            });
        }
        if(contactGroupIds.size() > 0){
            List<GroupInfo> groupInfos = this.groupInfoMapper.selectList(new LambdaQueryWrapper<GroupInfo>().select(GroupInfo::getGroupId, GroupInfo::getGroupName, GroupInfo::getGroupAvatar)
                    .in(GroupInfo::getGroupId, contactGroupIds));
            groupInfos.forEach(item -> {
                chatSessionUserList.forEach(it -> {
                    if(Objects.equals(it.getContactId(), item.getGroupId())){
                        it.setNickName(item.getGroupName());
                        it.setAvatar(item.getGroupAvatar());
                    }
                });
            });
        }
        log.info("获取到所有信息 {}", chatSessionUserList);
        ChatInitMessageVo chatInitMessageVo = new ChatInitMessageVo();
        chatInitMessageVo.setChatSessionUserList(chatSessionUserList);
        //查询聊天消息
        // 1. 查询我的sessionUser中的sessionId有哪些
        List<String> sessionIdList = chatSessionUserList.stream().map(ChatSessionUser::getSessionId).collect(Collectors.toList());
        // 2.根据sessionId查询聊天信息
//        List<String> userIdList = userContactList.stream().filter(item -> item.startsWith(UserContactTypeEnum.GROUP.getPrefix())).collect(Collectors.toList());
//        userIdList.add(userId);
        List<ChatMessage> chatMessageList = chatMessageMapper.selectMessagesBatch(sessionIdList, lastOffTime);
        //将所有消息进行解密处理
        chatMessageList.forEach(chatMessage -> {
            try{
                chatMessage.setMessageContent(AESUtils.decryptLargeData(chatMessage.getMessageContent()));
            }catch (Exception e){
                log.error("解密失败", e);
            }
        });
        chatInitMessageVo.setChatMessageList(chatMessageList);

        //查询好友申请人数
        Long count = userContactApplyMapper.selectCount(new LambdaQueryWrapper<UserContactApply>()
                .eq(UserContactApply::getReceiveUserId, userId)
                .eq(UserContactApply::getStatus, UserContactApplyStatusEnum.PENDING.getStatus()));
        chatInitMessageVo.setApplyCount(count.intValue());
        //更新用户最后连接时间
        UserInfo userInfo1 = new UserInfo();
        userInfo1.setUserId(userId);
        userInfo1.setLastOffTime(System.currentTimeMillis());
        userInfoMapper.updateById(userInfo1);
        //发送消息
        MessageSendVo<ChatInitMessageVo> messageSendVo = new MessageSendVo<>();
        messageSendVo.setMessageType(MessageTypeEnum.INIT.getType());
        messageSendVo.setContactId(userId);
        messageSendVo.setExtendData(chatInitMessageVo);
        sendMessage(messageSendVo, userId);
    }

    /**
     * 发送消息
     */
    private static void sendMessage(MessageSendVo messageSendVo, String receiveId){
        Channel channel = CHANNEL_CONCURRENT_HASH_MAP.get(receiveId);
        if(channel == null){
            return;
        }
        //相对于客户端而言，联系人就是发送人
        messageSendVo.setContactId(messageSendVo.getSendUserId());
        messageSendVo.setContactName(messageSendVo.getSendUserNickName());
        channel.writeAndFlush(new TextWebSocketFrame(JsonUtil.convertObj2Json(messageSendVo)));
    }
    public void sendMsg(MessageSendVo messageSendVo) {
        UserContactTypeEnum prefix = UserContactTypeEnum.getPrefix(messageSendVo.getContactId());
        switch (prefix){
            case USER:
                sendToUser(messageSendVo);
                break;
            case GROUP:
                sendToGroup(messageSendVo);
                break;
        }
    }

    //发送给群组
    private void sendToGroup(MessageSendVo messageSendVo) {
        String receiveId = messageSendVo.getContactId();
        if(receiveId == null){
            return;
        }
        ChannelGroup channels = CHANNEL_GROUP_CONCURRENT_HASH_MAP.get(receiveId);
        log.info("发送给群组{}, 并获取通道组{}",receiveId, channels);
        if(channels == null){
            if(messageSendVo.getMessageType().equals(MessageTypeEnum.GROUP_CREATE.getType())){
                //创建群组
                channels = new DefaultChannelGroup(GlobalEventExecutor.INSTANCE);
                CHANNEL_GROUP_CONCURRENT_HASH_MAP.put(receiveId, channels);
                //获取channel
                Channel channel = CHANNEL_CONCURRENT_HASH_MAP.get(messageSendVo.getSendUserId());
                addToGroup(receiveId, channel);
                log.info("创建群组{}", channels);
                channels.writeAndFlush(new TextWebSocketFrame(JsonUtil.convertObj2Json(messageSendVo)));
            }
            return;
        }
        if (messageSendVo.getMessageType().equals(MessageTypeEnum.ADD_GROUP.getType())) {
            //加入群聊
            Channel channel = CHANNEL_CONCURRENT_HASH_MAP.get(messageSendVo.getSendUserId());
            addToGroup(messageSendVo.getContactId(), channel);
        }
        channels.writeAndFlush(new TextWebSocketFrame(JsonUtil.convertObj2Json(messageSendVo)));
    }
    //发送给用户
    private void sendToUser(MessageSendVo messageSendVo) {
        String receiveId = messageSendVo.getContactId();
        if(receiveId == null){
            return;
        }
        //发送消息
        log.info("发送给用户{}", receiveId);
        sendMessage(messageSendVo, receiveId);
        //强制下线
        if(MessageTypeEnum.FORCE_OFF_LINE.getType().equals(messageSendVo.getMessageType())){
            //关闭通道
            closeContact(receiveId);
        }
    }

    private void addToGroup(String groupId, Channel channel){
        ChannelGroup group = CHANNEL_GROUP_CONCURRENT_HASH_MAP.get(groupId);
        if(group == null){
            group = new DefaultChannelGroup(GlobalEventExecutor.INSTANCE);
            CHANNEL_GROUP_CONCURRENT_HASH_MAP.put(groupId, group);
            return;
        }
        group.add(channel);
    }

    /**
     * 断开连接
     * @param channel
     */
    public void removeContext(Channel channel, String userId){
        //清除管道
        if(StringUtil.isEmpty(userId)){
            CHANNEL_CONCURRENT_HASH_MAP.remove(userId);
        }
        //清除心跳
        redisComponent.removeUserHeartbeat(userId);
        //关闭通道
//        channel.close();
        //更新用户最后离线时间
        UserInfo userInfo = new UserInfo();
        userInfo.setLastOffTime(System.currentTimeMillis());
        userInfo.setUserId(userId);
        userInfoMapper.updateById(userInfo);
    }

    /**
     * 关闭通道
     * @param userId
     */
    public void closeContact(String userId){
        if(StringUtil.isEmpty(userId)){
            return;
        }
        Channel channel = CHANNEL_CONCURRENT_HASH_MAP.get(userId);
        if(channel == null){
            return;
        }
        //删除tokenUserInfo
        redisComponent.removeTokenUserInfoDto(userId);
        channel.close();
    }


}
